package cn.bby.tools.utils.split;


import cn.hutool.core.io.FileUtil;
import com.intellij.util.ResourceUtil;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ben
 * @since 2025/9/24 16:55
 */
public class LinkWordSplitUtilImpl implements IWordSplitUtil {

    private final Map<Character, Node> map = new HashMap<>();

    private static final Map<String, LinkWordSplitUtilImpl> CACHE = new HashMap<>();

    public LinkWordSplitUtilImpl(List<String> words) {
        addWords(words);
    }

    public static LinkWordSplitUtilImpl getInstance() {
        return getInstance("tools", "words.txt");
    }

    public static LinkWordSplitUtilImpl getInstance(String basePath, String fileName) {
        return CACHE.computeIfAbsent(basePath + fileName, k -> new LinkWordSplitUtilImpl(FileUtil.readLines(
                ResourceUtil.getResource(LinkWordSplitUtilImpl.class.getClassLoader(), basePath, fileName),
                StandardCharsets.UTF_8)
        ));
    }

    public void addWords(Collection<String> words) {
        for (String word : words) {
            char[] charArray = word.trim().toLowerCase().toCharArray();
            Node curNode = map.computeIfAbsent(charArray[0], k1 -> new Node(k1, new HashMap<>()));
            for (int i = 1; i < charArray.length; i++) {
                curNode = curNode.next.computeIfAbsent(charArray[i], k -> new Node(k, new HashMap<>()));
            }
            curNode.isWord = true;
        }
    }

    @Override
    public List<String> doSplit(String str) {
        char[] charArray = str.trim().toLowerCase().toCharArray();
        if (charArray.length == 0) {
            return new ArrayList<>();
        }
        int startIdx = 0;
        Node node = null;
        List<String> res = new ArrayList<>();
        int lastWordEnd = -1;
        for (int i = 0; i < charArray.length; i++) {
            if (node == null) {
                startIdx = i;
                node = map.get(charArray[startIdx]);
                continue;
            }
            node = node.next.get(charArray[i]);
            if (node == null) {
                if (lastWordEnd > startIdx) {
                    res.add(new String(charArray, startIdx, lastWordEnd - startIdx + 1));
                    i = lastWordEnd;
                } else {
                    res.add(new String(charArray, startIdx, i - startIdx));
                    --i;
                }

                lastWordEnd = -1;
            } else if (node.isWord) {
                lastWordEnd = i;
            }
        }
        if (node != null) {
            res.add(new String(charArray, startIdx, charArray.length - startIdx));
        }
        return res;
    }

    public static class Node {
        public final Character ch;
        public final Map<Character, Node> next;
        boolean isWord;

        public Node(Character ch, Map<Character, Node> next) {
            this.ch = ch;
            this.next = next;
        }
    }
}
